﻿#pragma once
#include "XyNet/Common/SetMapHelper.h"
#include "XyNet/Common/Singleton.h"

namespace XyNet
{
	/// 主题，被观察的对象
	template <typename DerivedObserver>
	class Subject : public DefaultObject<Subject<DerivedObserver>>
	{
	public:
		Subject() : _enabled(true), _recursiveEnableLevel(0)
		{
		}

		~Subject()
		{
			for (const auto& pair : _observersMap)
			{
				auto& observers = pair.second;
				for (auto iter = observers.begin(); iter != observers.end();)
					removeObserver(*iter++);	// 同时重新设定观察者的观察对象为空
			}
		}

		/// 添加观察者
		void addObserver(DerivedObserver* observer)
		{
			int priority = observer->getPriority();
			SetMapHelper::insert(&_observersMap[priority], observer);
			observer->_subject = this;
		}

		/// 移除观察者
		void removeObserver(DerivedObserver* observer)
		{
			int priority = observer->getPriority();
			SetMapHelper::erase(&_observersMap[priority], observer);
			observer->_subject = nullptr;
		}

		/// 是否沉默
		bool isEnabled() const
		{
			return _enabled;
		}

		/// 设置沉默，沉默状态下不发送通知
		void setEnabled(bool enabled)
		{
			_enabled = enabled;
			if (_enabled)
				_recursiveEnableLevel = 0;
		}

		/// 设置递归沉默，沉默状态下不发送通知
		void setRecursiveEnabled(bool enabled)
		{
			if (enabled)
				_recursiveEnableLevel += 1;
			else
				_recursiveEnableLevel -= 1;

			if (_recursiveEnableLevel >= 0)
				setEnabled(true);
			else
				setEnabled(false);
		}

		/// 通知观察者
		template <typename Function>
		void notify(const Function& function)
		{
			if (_enabled)
			{
				for (const auto& pair : _observersMap)
				{
					const auto& observers = pair.second;
					for (const auto& listener : observers)
						function(listener);
				}
			}
		}

		/// 通知观察者，只要有一个观察者返回false则返回false，否则为true
		template <typename Function>
		bool notifyBool(const Function& function)
		{
			bool result = true;
			if (_enabled)
			{
				for (const auto& pair : _observersMap)
				{
					const auto& observers = pair.second;
					for (const auto& observer : observers)
					{
						if (!function(observer))
							result = false;
					}
				}
			}
			return result;
		}

	private:
		/// 观察者优先级映射，数值低的优先
		map<int, set<DerivedObserver*>> _observersMap;
		/// 是否启用，启用后才会通知观察者
		bool _enabled;
		/// 递归启动级别（0以上为启用，负数为禁用）
		int _recursiveEnableLevel;

#define XYNET_IMPLEMENT_DEFAULT_SUBJECT(type) \
		XYNET_IMPLEMENT_DEFAULT_OBJECT(Subject<type>)
	};

	//////////////////////////////////////////////////////////////////////////

	/// 禁用对象作用域
	template <typename Subject>
	class DisableSubjectScope : noncopyable
	{
	public:
		DisableSubjectScope(Subject* subject) : _subject(subject)
		{
			_subject->setEnabled(false);
		}

		~DisableSubjectScope()
		{
			_subject->setEnabled(true);
		}

	private:
		Subject* _subject;
	};

	//////////////////////////////////////////////////////////////////////////

	/// 递归禁用对象作用域
	template <typename Subject>
	class RecursiveDisableSubjectScope : noncopyable
	{
	public:
		RecursiveDisableSubjectScope(Subject* subject) : _subject(subject)
		{
			_subject->setRecursiveEnabled(false);
		}

		~RecursiveDisableSubjectScope()
		{
			_subject->setRecursiveEnabled(true);
		}

	private:
		Subject* _subject;
	};

	//////////////////////////////////////////////////////////////////////////////////////

	/// 观察者
	template <typename DerivedObserver>
	class Observer
	{
		friend class Subject < DerivedObserver >;

	public:
		Observer() : _subject(nullptr), _priority(0)
		{
			setSubject(Subject<DerivedObserver>::getDefault());
		}

		Observer(const Observer& other) : _subject(nullptr), _priority(0)
		{
			setPriority(other._priority);
			setSubject(other._subject);
		}

		virtual ~Observer()
		{
			setSubject(nullptr);	// 同时从观察目标中移除
		}

		const Observer& operator=(const Observer& other)
		{
			setPriority(other._priority);
			setSubject(other._subject);
			return *this;
		}

		/// 获取观察主体
		Subject<DerivedObserver>* getSubject() const
		{
			return _subject;
		}

		/// 设置观察主体
		void setSubject(Subject<DerivedObserver>* subject)
		{
			if (_subject != subject)
			{
				if (_subject)
					_subject->removeObserver(static_cast<DerivedObserver*>(this));
				if (subject)
					subject->addObserver(static_cast<DerivedObserver*>(this));
				_subject = subject;
			}
		}

		/// 获取优先级
		int getPriority() const
		{
			return _priority;
		}

		/// 设置优先级
		void setPriority(int priority)
		{
			if (_priority != priority)
			{
				if (_subject)
				{
					Subject<DerivedObserver>* subject = _subject;
					setSubject(nullptr);
					_priority = priority;
					setSubject(subject);
				}
				else
				{
					_priority = priority;
				}
			}
		}

	private:
		/// 所观察的主体
		Subject<DerivedObserver>* _subject;
		/// 优先级
		int _priority;
	};
}